<!--
 * @Author: Wanko
 * @Date: 2023-08-17 10:52:22
 * @LastEditors: Wanko
 * @LastEditTime: 2024-07-06 15:23:20
 * @Description: this._id.toString();
-->
<template>
  <div class="flex flex-col h-screen text-14">
    <div>
      <div class="p flex">
        <el-button @click="getRandom(1)">随机1个</el-button>
        <el-button @click="getRandom(10)">随机10个卡片</el-button>
        <el-input
          class="ml"
          v-model="searchQuery"
          ref="searchInputRef"
          @input="debouncedSearch"
          placeholder="请输入搜索关键词"
        ></el-input>
        <el-input class="ml" v-model="assignNumber" placeholder="指定数量"></el-input>
        <el-button @click="getRandom()">生成</el-button>
        <el-switch
          v-model="isReverse"
          inline-prompt
          active-text="倒序"
          inactive-text="顺序"
          @change="switchReverse"
        />
        <el-switch v-model="isInput" inline-prompt active-text="输入" inactive-text="输入" />
        <!-- <div>
      <input
        type="file"
        ref="fileInput"
        @change="handleFileUpload"
        accept=".md,.txt"
        id="fileInput"
      />
    </div> -->
        <div>{{ total }}</div>
      </div>
      <div class="p" v-if="isInput">
        <div class="relative">
          <el-input
            placeholder="写点什么"
            v-model="content"
            ref="contentRef"
            :autosize="{ minRows: 6, maxRows: 8 }"
            type="textarea"
          />
          <div class="absolute bottom-10 right-10">
            <el-button type="primary" :icon="Promotion" @click="onSubmit" ref="submitRef" />
          </div>
        </div>
      </div>
    </div>

    <!-- <el-row>
    <el-col :span="12">
      <el-input
        placeholder="请输入内容"
        v-model="content"
        ref="contentRef"
        type="textarea"
        :col="4"
      >
      </el-input>
    </el-col>
    
  </el-row> -->
    <!-- <div class="flex-1 bg-red">

    </div> -->
    <ul
      v-infinite-scroll="onLoad"
      class="flex-1"
      style="overflow: auto"
      infinite-scroll-distance="20"
      :infinite-scroll-immediate="false"
      :key="show"
    >
      <div class="waterfall p" ref="content">
        <!-- <li v-for="i in count" :key="i" class="infinite-list-item">{{ i }}</li> -->
        <el-card
          v-for="(i, index) in cards"
          :key="index"
          class="waterfall-item relative"
          shadow="hover"
          @mouseover="i.showOperate = true"
          @mouseleave="i.showOperate = false"
          @dblclick="handleDoubleClick(i)"
        >
          <div class="" v-html="renderedText(i.content)"></div>
          <template #footer>
            <div class="justify-end">
              <el-icon @click="onCardCopy(i.content)" class="mr-5"><CopyDocument /></el-icon>
              <el-icon class="mr-5" @click="openInputDialog(i)"><EditPen /></el-icon>
              <el-popconfirm
                title="确定删除吗?"
                confirm-button-text="确定"
                cancel-button-text="取消"
                @confirm="onDelete(i)"
                trigger="hover"
              >
                <template #reference>
                  <el-icon><Delete /></el-icon>
                </template>
              </el-popconfirm>
            </div>
          </template>
        </el-card>
      </div>
    </ul>
    <div class="waterfall p" v-if="searchList">
      <el-card
        v-for="(i, index) in searchList"
        :key="index"
        class="waterfall-item relative"
        shadow="hover"
        @mouseover="i.showOperate = true"
        @mouseleave="i.showOperate = false"
        @dblclick="handleDoubleClick(i)"
      >
        <div class="" v-html="renderTags(i.content)"></div>

        <template #footer>
          <div class="justify-end">
            <el-icon @click="onCardCopy(i.content)" class="mr-5"><CopyDocument /></el-icon>
            <el-icon class="mr-5" @click="openInputDialog(i)"><EditPen /></el-icon>
            <el-popconfirm
              title="确定删除吗?"
              confirm-button-text="确定"
              cancel-button-text="取消"
              @confirm="onDelete(i)"
              trigger="hover"
            >
              <template #reference>
                <el-icon><Delete /></el-icon>
              </template>
            </el-popconfirm>
          </div>
        </template>
      </el-card>
    </div>
    <el-dialog v-model="showInputDialog" width="30%" :show-close="false">
      <div class="relative">
        <el-input
          placeholder="写点什么"
          v-model="content"
          ref="dialogInputRef"
          :autosize="{ minRows: 6, maxRows: 8 }"
          type="textarea"
        />
        <div class="absolute bottom-10 right-10">
          <el-button type="primary" :icon="Promotion" @click="onSubmit" ref="dialogSubmitRef" />
        </div>
      </div>
    </el-dialog>

    <el-dialog
      v-model="dialogVisible"
      title="卡片"
      width="50%"
      :style="{ 'max-height': '80vh' }"
      class="overflow-hidden"
    >
      <el-scrollbar class="h-full" max-height="600px">
        <div class="card-text">
          <p v-for="(i, index) in list" :key="index">{{ i }}</p>
        </div>
      </el-scrollbar>
      <!-- <el-scrollbar style="max-height: 100%">
        <div class="card-text">
          <p v-for="(i, index) in list" :key="index">{{ i }}</p>
        </div>
      </el-scrollbar> -->

      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary" @click="onSwitch"> 换一个 </el-button>
          <el-button type="primary" @click="onCopy"> 复制 </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script>
// 引入loadsh
import _ from 'lodash'
import request from '@/request'
import hotkeys from 'hotkeys-js'
import axios from 'axios'
import { Promotion } from '@element-plus/icons-vue'
import { flomoUrl, flomoApi } from '../namespace.js'
export default {
  data() {
    return {
      isReverse: true, // 倒序
      isRandom: false, //
      isInput: false, // 展示输入框
      Promotion,
      visible: false,
      content: '',
      fileList: [],
      cards: [],
      list: [],
      dialogVisible: false,
      searchQuery: '',
      searchList: null,
      uploading: false,
      assignNumber: 30,
      shortcuts: {
        'command+/': this.focusInput,
        'command+enter': this.onSubmit,
        'command+b': this.onSubmit,
        'command+e': this.toggleInputDialog,
        'command+k': this.focusSearchInput
        // 可以继续添加其他快捷键和对应的操作函数
      },
      inputFocused: false,
      carouselList: [],
      initialIndex: 2,
      showInputDialog: false,
      count: 1,
      showCards: [],
      show: 0,
      page: 1,
      size: 50,
      total: 0
    }
  },
  computed: {
    renderedText() {
      return (text) => {
        return this.renderTags(text)
      }
    }
  },
  watch: {
    renderedText() {
      this.$nextTick(() => {
        this.addTagClickEvent()
      })
    }
  },
  created() {
    // 使用防抖函数包装 performSearch 方法，延迟执行 500 毫秒
    this.debouncedSearch = this.debounce(this.onSearch, 500)
    this.getList()
  },
  async mounted() {
    Object.entries(this.shortcuts).forEach(([shortcut, callback]) => {
      this.handleShortcuts(shortcut, callback)
    })
    this.observeDOMChanges()
    window.addEventListener('keydown', this.handleGlobalShortcut)
  },
  beforeUnmount() {
    // 遍历快捷键对象，动态移除全局快捷键监听
    Object.keys(this.shortcuts).forEach((shortcut) => {
      hotkeys.unbind(shortcut)
    })
  },
  methods: {
    observeDOMChanges() {
      const observer = new MutationObserver(() => {
        this.addTagClickEvent()
      })

      observer.observe(this.$refs.content, {
        childList: true,
        subtree: true
      })
    },
    onSend() {
      const timestamp = Math.floor(Date.now() / 1000)
      const str = `api_key=flomo_web&app_version=4.0&content=<p>memo的HTML</p>&created_at=${timestamp}&platform=web&timestamp=${timestamp}&tz=8:0&webp=1`
      let sign = md5(str)
      // sign = '0cdb39bc830eecbb147689791f087ac2'

      console.log('onsend', sign)
      axios.put(
        'https://flomoapp.com/api/v1/memo',
        {
          content: '233333',
          timestamp,
          api_key: 'flomo_web',
          sign,
          app_version: '4.0',
          created_at: timestamp,
          platform: 'web',
          tz: '8:0',
          webp: '1'
        },
        {
          headers: {
            Authorization: 'Bearer 4029272|KExwllKpE6ECTieJ5nj6DibZiJN2ATeS67hnV0Xj'
          }
        }
      )
    },

    onLoad() {
      this.page += 1
      this.getList(true)
    },
    /**
     * @description: 渲染标签
     * @param {*} text
     * @return {*}
     */
    renderTags(text) {
      // 使用正则表达式匹配以#开头的字，并添加标签样式
      return text.replace(
        /#([^#\s]+)(?=#|\s|$)/g,
        `<span class="tag rounded-4 bg-purple-light text-12 mx-2 px-4 py-2 whitespace-nowrap cursor-pointer" data-tag="$1">#$1</span>`
      )
    },
    tagClick(event) {
      console.log('🚀 ===>event：', event)
      const tag = event.target.dataset.tag
      // alert(`标签被点击: ${tag}`)
      console.log('🚀 ===>tag：', tag)
    },
    addTagClickEvent() {
      console.log('🚀 ===>1111：', 1111)
      const tags = this.$refs.content.querySelectorAll('.tag')
      tags.forEach((tag) => {
        tag.addEventListener('click', this.tagClick)
      })
    },
    /**
     * @description: 去除标签
     * @return {*}
     */
    trimTags(text) {
      return text.replace(/#([^#\s]+)(?=#|\s|$)/g, '').trim()
    },
    /**
     * @description: 处理双击事件的逻辑
     * @param {*} i
     * @return {*}
     */
    handleDoubleClick(i) {
      this.editItem = i
      this.content = i.content
      this.showInputDialog = true
    },
    openInputDialog(i) {
      this.showInputDialog = true
      this.editItem = i
      this.content = i.content
    },
    toggleInputDialog() {
      this.showInputDialog = !this.showInputDialog
      if (this.showInputDialog) {
        this.$nextTick(() => {
          this.focusInput()
        })
      }
    },
    switchReverse(flag) {
      this.cards = this.cards.reverse()
    },
    async onDelete(i) {
      const { id } = i
      await request.delete(`/cards/${id}`)
      this.$message.success('删除成功')
      this.visible = false
      this.getList()
      // this.updateFlomo(i, 0)
    },
    updateFlomo(i, flag) {
      let tag
      if (!flag) {
        tag = '删除'
      } else {
        tag = '更新'
      }
      let { content, tags, flomo_slug } = i
      if (!flomo_slug) return
      const url = `${flomoApi}${flomo_slug}`
      content = `${content} #${tag} ${url}`
      tags.push(tag)
      request.post(flomoUrl, { content, tags })
    },
    handleGlobalShortcut(event) {
      // 获取当前活动的 DOM 元素
      const activeElement = document.activeElement

      // 判断当前焦点是否在输入框内或者输入框的子元素中
      const isInputFocused =
        activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA')
      if (isInputFocused) {
        const submitKey =
          (event.metaKey && event.key === 'Enter') || (event.metaKey && event.key === 'b')

        const inputKey = event.metaKey && event.key === 'e'
        if (inputKey && !this.showInputDialog) {
          activeElement.blur()
          event.preventDefault()
          this.toggleInputDialog()
        }
        if (submitKey) {
          event.preventDefault()
          this.onSubmit()
        }
      }
      // // 如果焦点不在输入框内，则执行你期望的全局快捷键操作
      // if (!isInputFocused) {
      //   if (event.metaKey && event.key === '/') {
      //     event.preventDefault();
      //     this.focusInput();
      //   } else if (event.metaKey && event.key === 'Enter') {
      //     event.preventDefault();
      //     this.submitForm();
      //   }
      // }
    },

    handleShortcuts(action, callback) {
      hotkeys(action, (event, handler) => {
        // 阻止默认行为
        const activeElement = document.activeElement

        // 如果当前焦点不在 el-input 中，执行你期望的全局快捷键操作
        if (
          !activeElement ||
          (activeElement.tagName !== 'INPUT' && activeElement.tagName !== 'TEXTAREA')
        ) {
          // event.preventDefault()
          callback()
        }
      })
    },
    focusSearchInput() {
      this.$refs.searchInputRef.focus()
    },
    focusInput() {
      if (!this.showInputDialog) {
        this.$refs.contentRef.focus()
      } else {
        this.$nextTick(() => {
          this.$refs.dialogInputRef.focus()
        })
      }
    },
    submitForm() {
      // 调用 el-button 的提交方法
      this.$refs.submitRef.click()
    },
    extractTag(text) {
      // 匹配#号到下一个#号之间或#号到下一个空格之间的内容
      const regex = /#([^#\s]+)(?=#|\s|$)/g

      // 使用正则表达式的exec方法来提取匹配的内容
      let match

      const tagsSet = new Set() // 使用Set来进行标签的去重

      while ((match = regex.exec(text)) !== null) {
        const tag = match[1]
        tagsSet.add(tag)
      }

      // 将Set转换为数组
      const uniqueTags = Array.from(tagsSet)
      return uniqueTags
    },
    async onSubmit() {
      if (!this.content) return this.$message.error('请输入内容')
      try {
        let tags, content

        if (!this.content.includes('#')) {
          // 不包含标签，默认打上金句标签
          content = `${this.content} #金句`
          tags = ['金句']
        } else {
          // 包含标签，提取标签
          content = this.content
          tags = this.extractTag(this.content)
        }

        console.log(tags, content)
        if (this.editItem) {
          // 编辑
          const { id, flomo_slug } = this.editItem
          await request.put(`/cards/${id}`, { content, tags })
          this.$message.success('更新成功')
          this.showInputDialog = false
          this.editItem = null
          // this.updateFlomo({ flomo_slug, content, tags }, 1)
        } else {
          // const flomoResult = await request.post(flomoUrl, { content, tags })
          await request.post('/cards', { content, tags })

          this.$message.success('提交成功')
        }

        this.content = ''
        this.getList()
      } catch (error) {
        console.log(error, 'error')
        this.$message.error(error)
      }
    },
    clearSearch() {
      this.searchQuery = ''
      this.searchList = null
    },
    async getList(isLoad) {
      if (!isLoad) this.page = 1
      // this.clearSearch()
      const cards = await request.get('/cards', {
        params: {
          page: this.page,
          size: this.size,
          key: this.searchQuery
        }
      })
      console.log(cards)
      // this.total = total
      if (!this.searchQuery && isLoad) {
        this.cards = [...this.cards, ...cards.map((i) => ({ ...i, showOperate: false }))]
      } else {
        this.cards = cards
      }
      if (this.isRandom) {
        this.cards = _.shuffle(this.cards)
      }
    },
    async loadMarkdownFile() {
      try {
        // 使用 Webpack 的 require.context 来导入 .md 文件
        const markdownFileContext = require.context('./', false, /\.md$/)

        const paragraphs = markdownFileContext.split('\n\n') // 根据空行分割段落

        this.cards = paragraphs.map((i) => {
          return {
            content: i
          }
        })
      } catch (error) {
        console.error('无法加载 Markdown 文件：', error)
      }
    },
    handleFileUpload(event) {
      const fileInput = this.$refs.fileInput
      if (fileInput.files.length > 0) {
        const uploadedFile = fileInput.files[0]
        console.log(uploadedFile)
        if (uploadedFile.size) {
          const reader = new FileReader()
          reader.onload = (event) => {
            // 获取文件内容
            const fileContent = event.target.result
            console.log('文件内容:', fileContent)
            const paragraphs = fileContent.split('\n\n') // 根据空行分割段落
            console.log('段落数组:', paragraphs)

            this.cards = paragraphs.map((i) => {
              return {
                content: i
              }
            })
            // 在这里处理文件内容
            // 你可以将文件内容存储在 Vue 组件的数据中或进行其他处理
          }
          reader.readAsText(uploadedFile)
        } else {
          console.error('仅支持上传 .txt 文件')
        }
      }
    },

    onSearch() {
      this.cards = []
      this.getList()
    },
    debounce(func, delay = 500) {
      let timer
      return function () {
        const context = this
        const args = arguments
        clearTimeout(timer)
        timer = setTimeout(() => {
          func.apply(context, args)
        }, delay)
      }
    },

    async onCardCopy(content) {
      // content = this.trimTags(content)
      try {
        await navigator.clipboard.writeText(content)
        this.$message.success('复制成功')
      } catch (error) {
        this.$message.error('复制失败')
      }
      return
      const textArea = document.createElement('textarea')
      textArea.value = content
      document.body.appendChild(textArea)
      textArea.select()

      try {
        document.execCommand('copy')
        this.$message.success('Content copied to clipboard')
      } catch (error) {
        this.$message.error('Error copying content')
      }

      document.body.removeChild(textArea)
    },
    onCopy() {
      const element = document.querySelector('.card-text')
      this.copyAllPTagsText('.card-text')
    },
    onClick() {
      const maxLength = this.cards.length
      console.log(this.random(0, maxLength))
    },
    copyAllPTagsText(parentElementId) {
      // 获取父元素
      const parentElement = document.querySelector(parentElementId)

      // 获取所有 <p> 标签
      const pTags = parentElement.getElementsByTagName('p')

      // 创建一个文本区域用于保存文本内容
      const textarea = document.createElement('textarea')
      let copiedText = ''

      // 遍历 <p> 标签并将文本内容添加到 copiedText
      for (let i = 0; i < pTags.length; i++) {
        copiedText += pTags[i].textContent + '\n'
      }

      // 将文本内容设置到文本区域
      textarea.value = copiedText

      // 将文本区域添加到页面以便选择文本
      document.body.appendChild(textarea)

      // 选择文本并复制到剪贴板
      textarea.select()
      try {
        const successful = document.execCommand('copy')
        if (successful) {
          this.$message.success('文本已成功复制到剪贴板！')
        } else {
          alert('复制失败，请手动复制文本。')
        }
      } catch (err) {
        alert('复制失败，请手动复制文本。')
      } finally {
        // 删除文本区域
        document.body.removeChild(textarea)
      }
    },
    /**
     * @description: 获取随机卡片
     */    
    async getRandom(size) {

      if (size) this.assignNumber = size
      const cards = await request.get('/cards/randoms', {
        params: {
          size: this.assignNumber
        }
      })

      const list = cards.map((i, index) => {
        const content = this.trimTags(i.content)
        // if (total === 1) {
        //   return `${i.content}`
        // } else {
        //   return `${index + 1}、${content}`
        // }
        return `${index + 1}、${content}`
      })
      this.list = list
      this.dialogVisible = true
    },
    // 随机生成卡片
    onSwitch() {
      this.getRandom()
    },
    onGenerate(number) {
      this.assignNumber = number
      const maxLength = this.cards.length - 1
      const randomNumbers = this.getRandomUniqueNumbers(0, maxLength, number)

      const list = randomNumbers.map((i, index) => {
        const item = this.cards[i]
        const content = this.trimTags(item.content)

        if (randomNumbers.length === 1) {
          return `${content}`
        } else {
          return `${index + 1}、${content}`
        }
      })
      this.list = list
      this.dialogVisible = true
    },
    getRandomUniqueNumbers(min, max, count) {
      if (count > max - min + 1) {
        throw new Error('Count must be less than or equal to the range of numbers.')
      }

      const uniqueNumbers = new Set()

      while (uniqueNumbers.size < count) {
        const randomNumber = Math.floor(Math.random() * (max - min + 1)) + min
        uniqueNumbers.add(randomNumber)
      }

      return Array.from(uniqueNumbers)
    },
    random(min, max) {
      if (min >= 0 && max > 0 && max >= min) {
        let gab = max - min + 1
        return Math.floor(Math.random() * gab + min)
      } else {
        return 0
      }
    }
  }
}
</script>
<!-- <script setup>
import axios from 'axios'
import { onMounted } from 'vue'

onMounted(async () => {
  await getList()
})

async function getList() {
  const result = await axios.get('/mock/demo')
}
</script> -->

<style>
.custom-dialog {
  max-height: 80vh; /* 设置 el-card 的最大高度为屏幕高度 */
  overflow: auto; /* 使用滚动条处理内容溢出 */
}
.infinite-list {
  height: 300px;
  padding: 0;
  margin: 0;
  list-style: none;
}
.infinite-list-item {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50px;
  background: var(--el-color-primary-light-9);
  margin: 10px;
  color: var(--el-color-primary);
}
.infinite-list .infinite-list-item + .list-item {
  margin-top: 10px;
}
.waterfall {
  column-count: 5; /* 设置列数 */
  column-gap: 20px; /* 设置列之间的间距 */
}

.waterfall-item {
  break-inside: avoid; /* 防止卡片跨列 */
  margin-bottom: 20px; /* 设置卡片之间的垂直间距 */
}
.el-tooltip__popper {
  pointer-events: none;
}
@media screen and (max-width: 1200px) {
  .waterfall {
    column-count: 4;
  }
}

@media screen and (max-width: 900px) {
  .waterfall {
    column-count: 3;
  }
}

@media screen and (max-width: 600px) {
  .waterfall {
    column-count: 2;
  }
}

@media screen and (max-width: 400px) {
  .waterfall {
    column-count: 1;
  }
}
</style>
